import json
import os
import threading
import time

from  apilib.component import compManager , TComp
from  apilib.common.utils import TMqtt
class TPumpGroup:
    def __init__(self):
        self.info ={
            "groupCode":"" ,
            "groupName":"" ,
            "groupDesc":"" ,
            "groupTag":{}
        }
class TPumpVar:
    def __init__(self):
        self.info ={
            "varId":"" ,
            "varName":"" ,
            "varTag":{} ,
            "rules":{} ,
            "groupCodes":[]
        }

class TCompPump( TComp):
    def __init__(self):
        super().__init__()
        self.buckets={}
        self.handlers={
            "loadSettings": self.loadSettings,
            "saveSettings": self.saveSettings,
            "setGroup": self.setGroup,
            "getGroups": self.getGroups,
            "registVariant": self.registVariant,
            "setVarValue": self.setVarValue,
            "getValues": self.getVarValues,
        }
        self.autoStartServices={}
        self.groups ={}
        self.rules={}
        self.vars={}
        self.values={}
        self.mqClient = TMqtt()
        self.saveTime = time.time()
    def compInit(self):
        try:
            self.loadSettings()
            self.mqClient.settings = self.compSettings['mqtt']
            (threading.Thread(target=self.loopTrigger , daemon=True)).start()
            (threading.Thread(target=self.mqClient.connect , daemon=True)).start()
        except Exception as er:
            self.manager.log(er)
    def loadSettings(self):
        res = {
            "status":0
        }
        try:
            dataPath = self.compSettings['settingsPath']
            fn = os.path.join(dataPath , 'pumpSettings.json')
            if os.path.exists(fn):
                groups = []
                vars=[]
                with open(fn , 'w' , encoding='utf-8') as f:
                    try:
                        content = f.read()
                        settings = json.loads(content)
                        groups = settings['groups']
                        vars = settings['vars']
                    except Exception as ee:
                        self.manager.log(ee)
                    f.write(content)
                if len( groups)>0 :
                    for g in groups:
                        group = TPumpGroup()
                        group.info = g
                        self.groups[g['groupCode']] = group
                if len( vars)>0 :
                    for v in vars:
                        var = TPumpVar()
                        var.info = v
                        self.vars[g['varId']] = var

                res['status'] =1
        except Exception as er:
            self.manager.log(er)
        return res
    def saveSettings(self):
        res = {
            "status":0
        }
        try:
            setting = {
                "groups":[x.info for x in self.groups.values()],
                "vars" :[x.info for x in self.vars.values()]
            }
            content = json.dumps(setting , ensure_ascii=False)
            dataPath = self.compSettings['settingsPath']
            if not os.path.exists(dataPath):
                os.makedirs(dataPath, 0x777)
            fn = os.path.join(dataPath , 'pumpSettings.json')
            with open(fn , 'w' , encoding='utf-8') as f:
                f.write(content)
            res['status'] =1
        except Exception as er:
            self.manager.log(er)
        return res
    def setGroup(self ,groupCode , groupName , groupDesc , groupTag={}):
        res ={"status":0}
        try:
            if ( groupCode not in self.groups.keys()):
                group = TPumpGroup()
                group.info={
                    "groupCode":groupCode ,
                    "groupName":groupName ,
                    "groupDesc":groupDesc ,
                    "groupTag": groupTag
                }
                self.groups[groupCode] = group
            else:
                self.groups[groupCode].info['groupName'] = groupName
                self.groups[groupCode].info['groupDesc'] = groupDesc
                self.groups[groupCode].info['groupTag'] = groupTag
            self.saveSettings()
            res['status'] =1
        except Exception as er:
            self.manager.log(er)
        return  res
    def getGroups(self):
        res =[]
        try:
            res=[x.info for x in self.groups.values()]
        except Exception as er:
            self.manager.log(er)
        return res
    '''
    rules: dict{
        ruleType: int 
        threshold: 0.005
    }
    
    ruleType:
    0-不发送
    1-变化就发送（如开关量、报警信号、故障信号、状态值等)
    2-变化超过百分比就发发送，threshold 为变化率0.005表示千分之5
    3-变化绝对值超过阈值就发送，threshold 为变化量的绝对值 如10
    4-超过一定时间未发送就再次发送，threshold 为 时间阈值 
    '''
    def registVariant(self , varId , varName , rules , groupCodes , varTag):
        res ={"status":0}
        try:
            if varId not in self.vars.keys():
                self.vars[varId] = TPumpVar()
                self.vars[varId].info['varId'] = varId
            varInfo = self.vars[varId].info
            varInfo['varName'] = varName
            varInfo['rules'] = rules
            varInfo['groupCodes'] = groupCodes
            varInfo['varTag'] = varTag
            self.saveSettings()
            res['status'] =1
        except Exception as er:
            self.manager.log(er)
        return  res
    def setVarValue(self , varId , value):
        res={
            "status":0
        }
        try:
            if varId in self.vars.keys():
                if varId in self.values.keys():
                    self.values[varId]['v1'] = value
                else:
                    self.values[varId] ={
                        'varId': varId ,
                        "v1": value
                    }
                triggerFlag = (1 in self.vars[varId].info['rules'].keys()) and ( self.values[varId]['v0']!=value)
                if triggerFlag :
                    groupCodes = self.vars['varId'].info['groupCodes']
                    for groupCode in groupCodes:
                        topic = f"{self.compSettings['rootTopic']}/{groupCode}"
                        valueData ={}
                        valueData[varId] = value
                        self.values[varId]['lastTime'] = time.time()
                        self.values[varId]['v0'] = value
                        self.sendMsg( topic , json.dumps(valueData, ensure_ascii=False))

                res['status'] = 1
            else:
                res['status'] = -2000
        except Exception as er:
            self.manager.log(er)
        return  res
    def getVarValues(self , varIds =[]):
        res={}
        try:
            for varId in varIds:
                if varId in self.values.keys():
                    res[varId] = self.values[varId]['v1']
        except Exception as er:
            self.manager.log(er)
        return  res

    def enableTrigger(self , var ):
        res = False
        try:
            varId = var.info['varId']
            if varId in self.values.keys():
                valueInfo = self.values[varId]
                for ruleInfo in var.info['rules']:
                    ruleType = ruleInfo['ruleType']
                    threshold =  ruleInfo['threshold'] if 'threshold' in ruleInfo.keys() else 0
                    v0 = valueInfo['v0']
                    v1 = valueInfo['v1']
                    lastTime = valueInfo['lastTime']
                    '''
                    if ruleType == 1:
                        res = v0!=v1
                    '''
                    if ruleType == 2 :
                        if v0!=v1 :
                            res = threshold==0 or abs((v1-v0)*1.0/v0) > threshold
                    elif ruleType == 3 :
                        if v0!=v1 :
                            res = threshold==0 or abs(v1-v0) > threshold
                    elif ruleType == 4 :
                        res = (time.time() - lastTime ) > threshold

                    if res :
                        break
        except Exception as er:
            self.manager.log(er)
        return  res
    def getTriggerValues(self ):
        res ={
            "status":0,
            "values":{}
        }
        try:
            res['values'] = [ self.values[ x.info['varId'] ] for x in self.vars.values() if self.enableTrigger(x)]
            res['status'] = len( res['values'])
        except Exception as er:
            self.manager.log(er)
        return res
    def loopTrigger(self):
        try:
            interval = self.compSettings['interval']
            while 1>0:
                time.sleep(1)
                nowTm = time.time()
                if nowTm-interval > self.saveTime:
                    self.saveTime= nowTm
                    triggerData = self.getTriggerValues()
                    if triggerData['status']>0:
                        for groupCode in self.groups.keys():
                            groupValues = [x for x in triggerData['values'] if groupCode in  self.vars[x['varId']].info['groupCodes']]
                            dictValues = {}
                            for valueInfo in groupValues:
                                valueInfo['lastTime'] = nowTm
                                valueInfo['v0'] = ['v1']
                                dictValues[valueInfo['vid']] = valueInfo['v1']
                            topic = f"{self.compSettings['rootTopic']}/{groupCode}"
                            self.sendMsg( topic , json.dumps(dictValues, ensure_ascii=False))
        except Exception as er:
            self.manager.log(er)
    def sendMsg(self , topic , data):
        try:
            if self.mqClient.client.is_connected():
                self.mqClient.client.publish(topic = topic , payload=data , qos=0 , retain=False);
        except Exception as er:
            self.manager.log(er)
_settings = {
    "settingsPath":"/data/devhhinfo/pump",
    "interval":5,
    "rootTopic":'zniot/reals',
    "mqtt":{
        "host":"iot.zn-power.com",
        "port":30107,
        "uid":"admin",
        "pwd":"Hhuc1115" ,
        "subTopics":[],
        "reconnectTime": 5
    }
}
compManager.registComponentType('TCompPump' , TCompPump , _settings)

